﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using com.skype.api;
using com.skype.ipc;
using System.Threading;
using System.Windows.Threading;

namespace Hugo
{
    class Listeners : AccountListener,
                    ConversationListener,
                    ParticipantListener,
                    SkypeListener,
                    ConnectionListener,
                    MessageListener,
                    SmsListener
    {

        private MySession mySession;
        public Boolean appConnected = false;
        Conversation activeConversation = null;
        Participant[] activeConversationParticipants = null;

        public Listeners(MySession mySession)
        {
            this.mySession = mySession;
            Console.WriteLine("\tRegistering the listeners...");
            registerAllListeners();
        }

        public void registerAllListeners()
        {
            mySession.mySkype.registerConnectionListener(this);
            mySession.mySkype.registerAccountListener(this);
            mySession.mySkype.registerConversationListener(this);
            mySession.mySkype.registerParticipantListener(this);
            mySession.mySkype.registerSkypeListener(this);
            mySession.mySkype.registerMessageListener(this);
            mySession.mySkype.registerSmsListener(this);
        }

        public void unRegisterAllListeners()
        {
            mySession.mySkype.unRegisterAccountListener(this);
            mySession.mySkype.unRegisterConnectionListener(this);
            mySession.mySkype.unRegisterConversationListener(this);
            mySession.mySkype.unRegisterParticipantListener(this);
            mySession.mySkype.unRegisterSkypeListener(this);
            mySession.mySkype.unRegisterMessageListener(this);
            mySession.mySkype.unRegisterSmsListener(this);
        }

        /* AccountListener Override: Tutorial Handler - Account Properties.*/
        public void onPropertyChange(com.skype.api.Account affectedAccount, com.skype.api.Account.Property prop, int value, String svalue)
        {
            if (prop == Account.Property.P_STATUS)
            {
                Account.Status accountStatus = affectedAccount.getStatus();
                mySession.setLoginStatus(accountStatus);
                if (value == Account.Status.LOGGED_IN_VALUE)
                {
                    Console.WriteLine("Login complete.");
                }
                else if ((accountStatus == Account.Status.LOGGED_OUT) ||
                        (accountStatus == Account.Status.LOGGED_OUT_AND_PWD_SAVED))
                {
                    Console.WriteLine("Login in progress/Logout complete.");
                }
                else
                {
                    String otherStatus = "Account Status = " + accountStatus.toString();
                    Console.WriteLine(otherStatus);
                }
            }
            else if (prop == Account.Property.P_LOGOUT_REASON)
            {
                Account.LogoutReason logoutReason = affectedAccount.getLogoutReason();
                Console.WriteLine("logoutreason = " + logoutReason.toString());
            }
            else
            {
                String propName = prop.toString();
                Console.WriteLine(propName + " property changed!");
            }
        }

        /* ParticipantListener Override */
        public void onPropertyChange(com.skype.api.Participant obj, com.skype.api.Participant.Property prop, int value, String svalue)
        {
            Participant affectedParticipant = (Participant)obj;

            if (prop == Participant.Property.P_SOUND_LEVEL)
            {
                Console.WriteLine("Sound level changed to " + affectedParticipant.getSoundLevel() + " for " +
                        affectedParticipant.getIdentity());
            }
            else if (prop == Participant.Property.P_VOICE_STATUS)
            {
                Participant.VoiceStatus voiceStatus = affectedParticipant.getVoiceStatus();
                Console.WriteLine("Voice status changed to " + voiceStatus.toString() + " for " +
                        affectedParticipant.getIdentity());
            }
        }

        /* ParticipantListener Override. */
        public void onIncomingDtmf(com.skype.api.Participant obj, Participant.Dtmf dtmf)
        {
        }


        /* ConversationListener Override: Tutorial Handler - Conversation "Live Status". */
        public void onPropertyChange(com.skype.api.Conversation obj, com.skype.api.Conversation.Property prop, int value, String svalue)
        {
            if (prop == Conversation.Property.P_LOCAL_LIVE_STATUS)
            {
                Conversation affectedConversation = (Conversation)obj;
                Conversation.LocalLiveStatus liveStatus = affectedConversation.getLocalLiveStatus();
                Console.WriteLine("Live status changed to " + liveStatus.toString());
                switch (liveStatus.toString())
                {
                    case "RINGING_FOR_ME":
                        Console.WriteLine("RING RING...");
                        if (doPickUpCall())
                        {
                            Console.WriteLine("Conv: Call answered!");
                            activeConversation = affectedConversation;
                            activeConversationParticipants = affectedConversation.getParticipants(Conversation.ParticipantFilter.ALL);
                            mySession.callActive = true;
                        }
                        break;
                    case "RECENTLY_LIVE":
                    case "NONE":
                        activeConversation = null;
                        activeConversationParticipants = null;
                        mySession.callActive = false;
                        Console.WriteLine("Conv: Call has ended/never started.");
                        break;
                    case "IM_LIVE":
                        Console.WriteLine("Conv: Live session is up!");
                        break;
                    default:
                        Console.WriteLine("Conv - Ignoring LiveStatus " + liveStatus.toString());
                        break;
                }
            }
        }

        /** ConversationListener Override. */
        public void onSpawnConference(com.skype.api.Conversation obj, Conversation spawned)
        {
        }
        public void onParticipantListChange(com.skype.api.Conversation obj)
        {
        }

        public void onMessage(com.skype.api.Conversation obj, Message message)
        {
            Console.WriteLine("Incoming message, but this one is not handled " + message);
        }

        public void onMessage(Skype obj, Message message,
             Boolean changesInboxTimestamp, Message supersedesHistoryMessage, Conversation conversation)
        {
            Message.Type msgType = message.getType();
            if (msgType == Message.Type.POSTED_TEXT) {
                String msgAuthor = message.getAuthor();
                String msgBody = message.getBodyXml();


                if (msgAuthor != mySession.myAccountName) {
                    int msgTimeStamp = message.getTimestamp();
                    //Date dateTimeStamp = new Date((msgTimeStamp.longValue() * 1000L));
                    //DateFormat targetDateFmt = DateFormat.getDateTimeInstance();
                    Console.WriteLine(msgAuthor + " says " + msgBody);

                    if (msgAuthor.Equals(GlobalSettings.nurseSkypeID))
                    {
                        msgBody = Translate.translate(msgBody);
                    }

                    Thread Messagethread = new Thread(
                    new ThreadStart(delegate()
                    {
                        MainWindow.getInstance().Dispatcher.Invoke(
                          System.Windows.Threading.DispatcherPriority.Normal,
                          new Action(
                            delegate()
                            {
                                List<UIOption> options = new List<UIOption>();
                                NotificationUIPage p = new NotificationUIPage(msgAuthor + " says", msgBody, options);
                                MainWindow.enqueueNotification(p);
                            }
                        ));
                    }));
                    Messagethread.SetApartmentState(ApartmentState.STA);
                    Messagethread.Start();
                   
                }
            }
        }

        /* SkypeListener Override: Tutorial Handler - Conversation ListType.*/
        public void onConversationListChange(Skype obj, Conversation conversation, Conversation.ListType type, Boolean added)
        {

            Console.WriteLine("ConversationListChange fired on: " + conversation.getDisplayName());

            if (type == Conversation.ListType.LIVE_CONVERSATIONS)
            {
                Conversation.LocalLiveStatus liveStatus = conversation.getLocalLiveStatus();
                Console.WriteLine("Live status changed to " + liveStatus.toString());
                switch (liveStatus.toString())
                {
                    case "RINGING_FOR_ME":
                        activeConversation = conversation;
                        activeConversationParticipants = conversation.getParticipants(Conversation.ParticipantFilter.ALL);
                        conversation.join();
                        mySession.callActive = true;
                        break;
                    case "RECENTLY_LIVE":
                    case "NONE":
                        Console.WriteLine("Call finished.");
                        activeConversation = null;
                        activeConversationParticipants = null;
                        mySession.callActive = false;
                        break;
                    case "IM_LIVE":
                        Console.WriteLine("Live session is up.");
                        break;
                    default:
                        Console.WriteLine("Ignoring Conversation status " + liveStatus.toString());
                        break;
                }
            }
        }

        /** SkypeListener Override.*/
        public void onNewCustomContactGroup(Skype obj, ContactGroup group)
        {
        }

        public void onContactOnlineAppearance(Skype obj, Contact contact)
        {
        }

        public void onContactGoneOffline(Skype obj, Contact contact)
        {
        }

        public void onAvailableVideoDeviceListChange(Skype obj)
        {
            //int deviceCount;

            if (obj.getAvailableVideoDevices().count > 0)
            {
                Console.WriteLine("Video device list retrieved:");
                Console.WriteLine("Device Name: " + obj.getAvailableVideoDevices().deviceNames[0]);
                /*this->videoDeviceName = deviceNames[0];
                this->videoDeviceId = deviceIds[0];
                QString msg = "Picking ";
                msg.append( (const char*)videoDeviceName );
                dispatcher->log(msg);
                this->isVideoCapable = true;*/
            }
            else
            {
                Console.WriteLine("ERROR: no video devices found.");
            };
        }

        public void onAvailableDeviceListChange(Skype obj)
        {
        }

        public void onNrgLevelsChange(Skype obj)
        {
        }

        public void onProxyAuthFailure(Skype obj, Skype.ProxyType type)
        {
        }

        public void onH264Activated(Skype obj)
        {
        }

        public void onApp2AppDatagram(Skype obj, String appname, String stream, byte[] data)
        {
        }

        public void onQualityTestResult(Skype skyobject, Skype.QualityTestType testType, Skype.QualityTestResult testResult,
                String withUser, String details, String xmlDetails)
        {
        }

        public void onApp2AppStreamListChange(Skype skyobject, String appname, Skype.App2AppStreams listType, String[] streams, int[] receivedSizes)
        {
        }


        /* ConnectionListener Override - Disconnect.*/
        public void sidOnDisconnected(String cause)
        {
            Console.WriteLine("Disconnected; reason = " + cause);
        }

        /* ConnectionListener Override - Connect.*/
        public void sidOnConnected()
        {
            Console.WriteLine("Connected!");
        }

        /* ConnectionListener Override - Connect in progress.*/

        public void sidOnConnecting()
        {
            Console.WriteLine("Connecting...");
        }

        public Boolean doPickUpCall()
        {
            Conversation[] liveConversations = mySession.mySkype.getConversationList(Conversation.ListType.LIVE_CONVERSATIONS);
            if (liveConversations.Length == 0)
            {
                Console.WriteLine("No live conversations to pick up!");
                return (false);
            }

            Conversation targetConversation = liveConversations[0];

            Participant[] callerList = targetConversation.getParticipants(Conversation.ParticipantFilter.OTHER_CONSUMERS);
            String displayParticipantsStr = "";

            int i;
            int j = callerList.Length;
            for (i = 0; i < j; i++)
            {
                displayParticipantsStr = displayParticipantsStr + " " + callerList[i].getIdentity();
            }

            Conversation.LocalLiveStatus liveStatus = targetConversation.getLocalLiveStatus();
            switch (liveStatus.toString())
            {
                case "RINGING_FOR_ME":
                    Console.WriteLine("RING RING...");
                    Console.WriteLine("Incoming call from: %s %n", displayParticipantsStr);
                    targetConversation.joinLiveSession(targetConversation.getJoinBlob());
                    return (true);
                // break;
                case "IM_LIVE":
                    Console.WriteLine("Another call is coming in from : %s %n", displayParticipantsStr);
                    Console.WriteLine("As we already have a live session up, we will reject it.");
                    targetConversation.leaveLiveSession(true);
                    break;
                default:
                    Console.WriteLine("Ignoring LiveStatus " + liveStatus.toString());
                    break;
            }

            return (false);
        }

        public void onPropertyChange(Message m, Message.Property mp, int i, string str)
        {
            Console.WriteLine(m.getAuthor() + " sent a message at " + m.getTimestamp().ToString() + " - " + str);
        }

        public void onPropertyChange(Sms s, Sms.Property sp, int i, string str)
        {
            Console.WriteLine(s.getTargetNumbers().ToString() + " sent a sms at " + s.getTimestamp().ToString() + " - " + str);
        }
    }

}